<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
  <meta name="theme-color" content="#222">
  <meta name="generator" content="Hexo 5.4.0">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

  <link rel="stylesheet" href="/css/main.css">



  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@5.15.2/css/all.min.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/animate.css@3.1.1/animate.min.css">

  <script class="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {
      "hostname": "holidaypenguin.gitee.io",
      "root": "/",
      "images": "/images",
      "scheme": "Mist",
      "version": "8.2.2",
      "exturl": false,
      "sidebar": {
        "position": "right",
        "display": "always",
        "padding": 18,
        "offset": 12
      },
      "copycode": true,
      "bookmark": {
        "enable": false,
        "color": "#222",
        "save": "auto"
      },
      "fancybox": false,
      "mediumzoom": false,
      "lazyload": false,
      "pangu": false,
      "comments": {
        "style": "tabs",
        "active": null,
        "storage": true,
        "lazyload": false,
        "nav": null
      },
      "motion": {
        "enable": true,
        "async": true,
        "transition": {
          "post_block": "fadeIn",
          "post_header": "fadeInDown",
          "post_body": "fadeInDown",
          "coll_header": "fadeInLeft",
          "sidebar": "slideUpIn"
        }
      },
      "prism": false,
      "i18n": {
        "placeholder": "搜索...",
        "empty": "没有找到任何搜索结果：${query}",
        "hits_time": "找到 ${hits} 个搜索结果（用时 ${time} 毫秒）",
        "hits": "找到 ${hits} 个搜索结果"
      },
      "path": "/search.xml",
      "localsearch": {
        "enable": true,
        "trigger": "auto",
        "top_n_per_article": 1,
        "unescape": false,
        "preload": false
      }
    };
  </script>
  <meta property="og:type" content="article">
  <meta property="og:title" content="iPhoneX安全区域(Safe Area)底部小黑条在微信小程序和H5的屏幕适配">
  <meta property="og:url" content="https://holidaypenguin.gitee.io/blob/2020-09-09-the-small-black-bar-at-the-bottom-of-the-iphone-x-safe-area-adapts-between-the-wechat-applet-and-the-h5-screen/index.html">
  <meta property="og:site_name" content="HolidayPenguin">
  <meta property="og:locale" content="zh_CN">
  <meta property="og:image" content="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/">
  <meta property="og:image" content="https://holidaypenguin.gitee.io/images/FrontEnd/2530160-1e6a1fcbc0499b86.webp">
  <meta property="og:image" content="https://holidaypenguin.gitee.io/images/FrontEnd/2530160-e1458ca07e5cb144.webp">
  <meta property="og:image" content="https://holidaypenguin.gitee.io/images/FrontEnd/2530160-749b1110fedb55ef.webp">
  <meta property="og:image" content="https://holidaypenguin.gitee.io/images/FrontEnd/2530160-3554ca94b5fa64d4.webp">
  <meta property="article:published_time" content="2020-09-09T06:32:44.000Z">
  <meta property="article:modified_time" content="2020-09-09T06:32:44.000Z">
  <meta property="article:author" content="holidaypenguin">
  <meta property="article:tag" content="iPhone安全区域">
  <meta property="article:tag" content="Safe Area">
  <meta property="article:tag" content="适配">
  <meta name="twitter:card" content="summary">
  <meta name="twitter:image" content="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/">


  <link rel="canonical" href="https://holidaypenguin.gitee.io/blob/2020-09-09-the-small-black-bar-at-the-bottom-of-the-iphone-x-safe-area-adapts-between-the-wechat-applet-and-the-h5-screen/">


  <script class="page-configurations">
    // https://hexo.io/docs/variables.html
    CONFIG.page = {
      sidebar: "",
      isHome: false,
      isPost: true,
      lang: 'zh-CN'
    };
  </script>
  <title>iPhoneX安全区域(Safe Area)底部小黑条在微信小程序和H5的屏幕适配 | HolidayPenguin</title>





  <noscript>
    <style>
      body {
        margin-top: 2rem;
      }

      .use-motion .menu-item,
      .use-motion .sidebar,
      .use-motion .post-block,
      .use-motion .pagination,
      .use-motion .comments,
      .use-motion .post-header,
      .use-motion .post-body,
      .use-motion .collection-header {
        visibility: visible;
      }

      .use-motion .header,
      .use-motion .site-brand-container .toggle,
      .use-motion .footer {
        opacity: initial;
      }

      .use-motion .site-title,
      .use-motion .site-subtitle,
      .use-motion .custom-logo-image {
        opacity: initial;
        top: initial;
      }

      .use-motion .logo-line {
        transform: scaleX(1);
      }

      .search-pop-overlay,
      .sidebar-nav {
        display: none;
      }

      .sidebar-panel {
        display: block;
      }
    </style>
  </noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage" class="use-motion">
  <div class="headband"></div>

  <main class="main">
    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner">
        <div class="site-brand-container">
          <div class="site-nav-toggle">
            <div class="toggle" aria-label="切换导航栏" role="button">
              <span class="toggle-line"></span>
              <span class="toggle-line"></span>
              <span class="toggle-line"></span>
            </div>
          </div>

          <div class="site-meta">

            <a href="/" class="brand" rel="start">
              <i class="logo-line"></i>
              <h1 class="site-title">HolidayPenguin</h1>
              <i class="logo-line"></i>
            </a>
          </div>

          <div class="site-nav-right">
            <div class="toggle popup-trigger">
              <i class="fa fa-search fa-fw fa-lg"></i>
            </div>
          </div>
        </div>



        <nav class="site-nav">
          <ul class="main-menu menu">
            <li class="menu-item menu-item-home"><a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a></li>
            <li class="menu-item menu-item-tags"><a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a></li>
            <li class="menu-item menu-item-categories"><a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a></li>
            <li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a></li>
            <li class="menu-item menu-item-search">
              <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
              </a>
            </li>
          </ul>
        </nav>



        <div class="search-pop-overlay">
          <div class="popup search-popup">
            <div class="search-header">
              <span class="search-icon">
                <i class="fa fa-search"></i>
              </span>
              <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off" maxlength="80" placeholder="搜索..." spellcheck="false" type="search" class="search-input">
              </div>
              <span class="popup-btn-close" role="button">
                <i class="fa fa-times-circle"></i>
              </span>
            </div>
            <div class="search-result-container no-result">
              <div class="search-result-icon">
                <i class="fa fa-spinner fa-pulse fa-5x"></i>
              </div>
            </div>

          </div>
        </div>

      </div>


      <div class="toggle sidebar-toggle" role="button">
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
        <span class="toggle-line"></span>
      </div>

      <aside class="sidebar">

        <div class="sidebar-inner sidebar-nav-active sidebar-toc-active">
          <ul class="sidebar-nav">
            <li class="sidebar-nav-toc">
              文章目录
            </li>
            <li class="sidebar-nav-overview">
              站点概览
            </li>
          </ul>

          <div class="sidebar-panel-container">
            <!--noindex-->
            <div class="post-toc-wrap sidebar-panel">
              <div class="post-toc animated">
                <ol class="nav">
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%89%8D%E8%A8%80"><span class="nav-number">1.</span> <span class="nav-text">前言</span></a></li>
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#1-%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D%EF%BC%9F"><span class="nav-number">2.</span> <span class="nav-text">1. 安全区域是什么意思？</span></a>
                    <ol class="nav-child">
                      <li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F"><span class="nav-number">2.1.</span> <span class="nav-text">安全区域</span></a></li>
                    </ol>
                  </li>
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#2-%E5%9C%A8%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%B8%8A%E9%80%82%E9%85%8D%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F"><span class="nav-number">3.</span> <span class="nav-text">2. 在微信小程序上适配安全区域</span></a>
                    <ol class="nav-child">
                      <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%96%B9%E6%A1%88%E4%B8%80%EF%BC%9A%E4%BD%BF%E7%94%A8%E5%B7%B2%E7%9F%A5%E5%BA%95%E9%83%A8%E5%B0%8F%E9%BB%91%E6%9D%A1%E9%AB%98%E5%BA%A634px-68rpx%E6%9D%A5%E9%80%82%E9%85%8D%EF%BC%88%E4%B8%8D%E6%8E%A8%E8%8D%90%EF%BC%89"><span class="nav-number">3.1.</span> <span class="nav-text">方案一：使用已知底部小黑条高度34px&#x2F;68rpx来适配（不推荐）</span></a>
                        <ol class="nav-child">
                          <li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%97%AE%E9%A2%98%EF%BC%9A%E5%A6%82%E4%BD%95%E5%88%A4%E6%96%AD%E5%BD%93%E5%89%8D%E6%9C%BA%E5%9E%8B%E6%98%AF%E9%9C%80%E8%A6%81%E9%80%82%E9%85%8D%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F"><span class="nav-number">3.1.1.</span> <span class="nav-text">问题：如何判断当前机型是需要适配安全区域</span></a></li>
                          <li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E4%B8%80%EF%BC%9A%E4%BD%BF%E7%94%A8wx-getSystemInfoSync-%E7%9A%84model%E5%B1%9E%E6%80%A7%E5%88%A4%E6%96%AD"><span class="nav-number">3.1.2.</span> <span class="nav-text">方法一：使用wx.getSystemInfoSync()的model属性判断</span></a></li>
                          <li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%96%B9%E6%B3%95%E4%BA%8C%EF%BC%9A%E4%BD%BF%E7%94%A8wx-getSystemInfoSync-%E4%B8%AD%E7%9A%84screenHeight%E5%92%8CsafeArea%E5%AF%B9%E8%B1%A1%E7%9A%84bottom%E5%B1%9E%E6%80%A7%E5%88%A4%E6%96%AD"><span class="nav-number">3.1.3.</span> <span class="nav-text">方法二：使用wx.getSystemInfoSync()中的screenHeight和safeArea对象的bottom属性判断</span></a></li>
                        </ol>
                      </li>
                      <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%96%B9%E6%A1%88%E4%BA%8C%EF%BC%9A%E4%BD%BF%E7%94%A8%E5%BE%AE%E4%BF%A1%E5%AE%98%E6%96%B9API%EF%BC%8CgetSystemInfo-%E4%B8%AD%E7%9A%84safeArea%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8C%E9%80%82%E9%85%8D%EF%BC%88%E6%8E%A8%E8%8D%90%EF%BC%89"><span class="nav-number">3.2.</span> <span class="nav-text">方案二：使用微信官方API，getSystemInfo()中的safeArea对象进行适配（推荐）</span></a></li>
                      <li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%96%B9%E6%A1%88%E4%B8%89%EF%BC%9A%E4%BD%BF%E7%94%A8%E8%8B%B9%E6%9E%9C%E5%AE%98%E6%96%B9%E6%8E%A8%E5%87%BA%E9%80%82%E9%85%8D%E6%96%B9%E6%A1%88css%E5%87%BD%E6%95%B0env-%E3%80%81constant-%E6%9D%A5%E9%80%82%E9%85%8D-%EF%BC%88%E6%8E%A8%E8%8D%90%EF%BC%89"><span class="nav-number">3.3.</span> <span class="nav-text">方案三：使用苹果官方推出适配方案css函数env()、constant()来适配 （推荐）</span></a></li>
                    </ol>
                  </li>
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#3-%E5%9C%A8H5%E4%B8%8A%E9%80%82%E9%85%8D%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F"><span class="nav-number">4.</span> <span class="nav-text">3. 在H5上适配安全区域</span></a></li>
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#%E6%B3%A8%E6%84%8F"><span class="nav-number">5.</span> <span class="nav-text">注意</span></a></li>
                  <li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%8F%82%E8%80%83"><span class="nav-number">6.</span> <span class="nav-text">参考</span></a></li>
                </ol>
              </div>
            </div>
            <!--/noindex-->

            <div class="site-overview-wrap sidebar-panel">
              <div class="site-author site-overview-item animated" itemprop="author" itemscope itemtype="http://schema.org/Person">
                <p class="site-author-name" itemprop="name">holidaypenguin</p>
                <div class="site-description" itemprop="description"></div>
              </div>
              <div class="site-state-wrap site-overview-item animated">
                <nav class="site-state">
                  <div class="site-state-item site-state-posts">
                    <a href="/archives/">

                      <span class="site-state-item-count">138</span>
                      <span class="site-state-item-name">日志</span>
                    </a>
                  </div>
                  <div class="site-state-item site-state-categories">
                    <a href="/categories/">

                      <span class="site-state-item-count">26</span>
                      <span class="site-state-item-name">分类</span></a>
                  </div>
                  <div class="site-state-item site-state-tags">
                    <a href="/tags/">

                      <span class="site-state-item-count">234</span>
                      <span class="site-state-item-name">标签</span></a>
                  </div>
                </nav>
              </div>
              <div class="links-of-author site-overview-item animated">
                <span class="links-of-author-item">
                  <a href="https://github.com/holidaypenguin" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;holidaypenguin" rel="noopener" target="_blank"><i class="github fa-fw"></i>GitHub</a>
                </span>
                <span class="links-of-author-item">
                  <a href="mailto:songshipeng2016@gmail.com" title="E-Mail → mailto:songshipeng2016@gmail.com" rel="noopener" target="_blank"><i class="envelope fa-fw"></i>E-Mail</a>
                </span>
              </div>



            </div>
          </div>
        </div>
      </aside>
      <div class="sidebar-dimmer"></div>


    </header>


    <div class="back-to-top" role="button">
      <i class="fa fa-arrow-up"></i>
      <span>0%</span>
    </div>

    <noscript>
      <div class="noscript-warning">Theme NexT works best with JavaScript enabled</div>
    </noscript>


    <div class="main-inner post posts-expand">





      <div class="post-block">



        <article itemscope itemtype="http://schema.org/Article" class="post-content" lang="zh-CN">
          <link itemprop="mainEntityOfPage" href="https://holidaypenguin.gitee.io/blob/2020-09-09-the-small-black-bar-at-the-bottom-of-the-iphone-x-safe-area-adapts-between-the-wechat-applet-and-the-h5-screen/">

          <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
            <meta itemprop="image" content="/images/avatar.gif">
            <meta itemprop="name" content="holidaypenguin">
            <meta itemprop="description" content="">
          </span>

          <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
            <meta itemprop="name" content="HolidayPenguin">
          </span>
          <header class="post-header">
            <h1 class="post-title" itemprop="name headline">
              iPhoneX安全区域(Safe Area)底部小黑条在微信小程序和H5的屏幕适配
            </h1>

            <div class="post-meta-container">
              <div class="post-meta">
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-calendar"></i>
                  </span>
                  <span class="post-meta-item-text">发表于</span>

                  <time title="创建时间：2020-09-09 14:32:44" itemprop="dateCreated datePublished" datetime="2020-09-09T14:32:44+08:00">2020-09-09</time>
                </span>
                <span class="post-meta-item">
                  <span class="post-meta-item-icon">
                    <i class="far fa-folder"></i>
                  </span>
                  <span class="post-meta-item-text">分类于</span>
                  <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                    <a href="/categories/CSS/" itemprop="url" rel="index"><span itemprop="name">CSS</span></a>
                  </span>
                </span>


                <span id="/blob/2020-09-09-the-small-black-bar-at-the-bottom-of-the-iphone-x-safe-area-adapts-between-the-wechat-applet-and-the-h5-screen/" class="post-meta-item leancloud_visitors" data-flag-title="iPhoneX安全区域(Safe Area)底部小黑条在微信小程序和H5的屏幕适配" title="阅读次数">
                  <span class="post-meta-item-icon">
                    <i class="far fa-eye"></i>
                  </span>
                  <span class="post-meta-item-text">阅读次数：</span>
                  <span class="leancloud-visitors-count"></span>
                </span>
              </div>

              <div class="post-description">
                <!-- more -->
              </div>
            </div>
          </header>




          <div class="post-body" itemprop="articleBody">
            <p><a target="_blank" rel="noopener" href="https://github.com/jwenjian/visitor-count-badge"><img src="" data-original="https://visitor-badge.glitch.me/badge?page_id=holidaypenguin.gitee.io/" alt="总访客数量"></a></p>
            <blockquote>
              <p>转载：<a target="_blank" rel="noopener" href="https://www.jianshu.com/p/4e410eddff66">https://www.jianshu.com/p/4e410eddff66</a></p>
            </blockquote>
            <p>最近写小程序时，遇到了 iPhoneX 底部小黑线与内容重叠的问题，实际上是iPhoneX安全区域的适配问题，了解清楚这个问题花了挺多时间的，也实操出了结果，忍不住来总结总结。</p>
            <h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1>
            <p>在苹果 iPhoneX 、iPhone XR等设备上，可以看到物理Home键被取消，改为底部小黑条替代home键功能。微信小程序和 h5 网页需要针对这种情况进行适配，否则可能会遇到底部按钮或选项卡栏与底部黑线重叠的情况，如下图。</p>
            <p><img src="" data-original="/images/FrontEnd/2530160-1e6a1fcbc0499b86.webp" alt="iPhoneX小黑条与按钮重叠.jpg"></p>
            <h1 id="1-安全区域是什么意思？"><a href="#1-安全区域是什么意思？" class="headerlink" title="1. 安全区域是什么意思？"></a>1. 安全区域是什么意思？</h1>
            <p>想要解决内容与小黑线重叠的问题，我们需要先了解清楚苹果对于安全区域的定义。</p>
            <h2 id="安全区域"><a href="#安全区域" class="headerlink" title="安全区域"></a>安全区域</h2>
            <blockquote>
              <p>安全区域指的是一个可视窗口范围，处于安全区域的内容不受圆角(corners)、齐刘海(sensor housing)、小黑条(Home Indicator)的影响。</p>
            </blockquote>
            <p>看看苹果官方给的这2张图就明白了，中间蓝色区域即为安全区域。也就是说，适配安全区域也就是让小程序或者H5的内容显示在蓝色区域部分。</p>
            <p><img src="" data-original="/images/FrontEnd/2530160-e1458ca07e5cb144.webp" alt="iphone-安全区域.png"></p>
            <p>同时安全区域是在IOS11之后并且是iPhoneX及以上机型才有的，所以需要适配的是这一类机型（为了方便，下文中统称这类需要适配的机型为iPhoneX），更老的机型则不需要考虑适配问题。</p>
            <h1 id="2-在微信小程序上适配安全区域"><a href="#2-在微信小程序上适配安全区域" class="headerlink" title="2. 在微信小程序上适配安全区域"></a>2. 在微信小程序上适配安全区域</h1>
            <p>三种方案：</p>
            <ul>
              <li>使用已知底部小黑条高度34px/68rpx来适配（不推荐）</li>
              <li>使用微信官方API，getSystemInfo()中的safeArea对象进行适配（推荐）</li>
              <li>使用苹果官方推出的css函数env()、constant()适配（推荐）</li>
            </ul>
            <h2 id="方案一：使用已知底部小黑条高度34px-68rpx来适配（不推荐）"><a href="#方案一：使用已知底部小黑条高度34px-68rpx来适配（不推荐）" class="headerlink" title="方案一：使用已知底部小黑条高度34px/68rpx来适配（不推荐）"></a>方案一：使用已知底部小黑条高度34px/68rpx来适配（不推荐）</h2>
            <p>这是比较老的方法，跟方案2、3比已经不推荐了，大家可以了解了解，着急可以直接看方案2和3。</p>
            <p>从网上了解到，iPhone底部的小黑条（Home Indicator）高度是34px，实际我也在真机确认了是34px，所以可以根据该值，设置底部按钮或选项卡的margin-bottom、padding-bottom、height等，或者添加一个div来占位小黑条的位置。</p>
            <p>这样做要有一个前提，需要判断当前机型是需要适配安全区域的机型。</p>
            <h3 id="问题：如何判断当前机型是需要适配安全区域"><a href="#问题：如何判断当前机型是需要适配安全区域" class="headerlink" title="问题：如何判断当前机型是需要适配安全区域"></a>问题：如何判断当前机型是需要适配安全区域</h3>
            <p>2种方案：</p>
            <ul>
              <li>使用<code>wx.getSystemInfoSync()</code>的<code>model</code>属性判断</li>
              <li>使用<code>wx.getSystemInfoSync()</code>中的<code>screenHeight</code>和<code>safeArea</code>对象的<code>bottom</code>属性判断</li>
            </ul>
            <h3 id="方法一：使用wx-getSystemInfoSync-的model属性判断"><a href="#方法一：使用wx-getSystemInfoSync-的model属性判断" class="headerlink" title="方法一：使用wx.getSystemInfoSync()的model属性判断"></a>方法一：使用<code>wx.getSystemInfoSync()</code>的<code>model</code>属性判断</h3>
            <p>已知市面上已有的带安全区域的苹果设备包括iPhone X、iPhone XR、iPhone XS Max、iPhone 11、iPhone 11 Pro、iPhone 11 Pro Max，所以可以直接从getSystemInfoSync()方法中拿到model属性进行判断。iPhone系列微信还未适配手机的model返回值为unknown(iphone)，也可以提前做适配。</p>
            <figure class="highlight javascript">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="keyword">let</span> IPHONE_X = <span class="regexp">/iphone x/i</span></span><br><span class="line"><span class="keyword">let</span> IPHONE_X_11 = <span class="regexp">/iphone 11/i</span></span><br><span class="line"><span class="keyword">let</span> IPHONE_UNKNOWN = <span class="regexp">/unknown\(iphone\)/i</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//方法一：使用model判断是否是IPhoneX及其他包含安全区域的机型手机</span></span><br><span class="line"><span class="keyword">const</span> isIPhoneX = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> model = wx.getSystemInfoSync().model</span><br><span class="line">  <span class="keyword">return</span> (model.search(IPHONE_X) &gt; -<span class="number">1</span> || model.search(IPHONE_X_11) &gt; -<span class="number">1</span> ||</span><br><span class="line">    model.search(IPHONE_UNKNOWN) &gt; -<span class="number">1</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//也可以使用正则表达式判断</span></span><br><span class="line"><span class="keyword">const</span> isIPhoneXRegex = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> model = wx.getSystemInfoSync().model</span><br><span class="line">  <span class="keyword">return</span> (<span class="regexp">/iphone\sx/i</span>.test(model)</span><br><span class="line">    || (<span class="regexp">/iphone/i</span>.test(model) &amp;&amp; <span class="regexp">/unknown/</span>.test(model))</span><br><span class="line">    || <span class="regexp">/iphone\s11/i</span>.test(model)) </span><br><span class="line">&#125;</span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <h3 id="方法二：使用wx-getSystemInfoSync-中的screenHeight和safeArea对象的bottom属性判断"><a href="#方法二：使用wx-getSystemInfoSync-中的screenHeight和safeArea对象的bottom属性判断" class="headerlink" title="方法二：使用wx.getSystemInfoSync()中的screenHeight和safeArea对象的bottom属性判断"></a>方法二：使用<code>wx.getSystemInfoSync()</code>中的<code>screenHeight</code>和<code>safeArea</code>对象的<code>bottom</code>属性判断</h3>
            <p>这里使用<code>screenHeight</code>而不是<code>windowHeight</code>，因为<code>bottom</code>是以屏幕左上角为原点开始计算的，所以需要的是屏幕高度，对比<code>screenHeight</code>和<code>bottom</code>，如果相等则说明不需要适配，不相等则需要适配。</p>
            <p><strong>注意：</strong>如果使用微信开发者工具中的模拟器，screenHeight和bottom始终是相等的，需要用真机来测试。</p>
            <figure class="highlight javascript">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="comment">//方法二：使用wx.getSystemInfoSync()中的screenHeight和safeArea的bottom判断</span></span><br><span class="line"><span class="keyword">const</span> isIPhoneX = <span class="function">() =&gt;</span> &#123;</span><br><span class="line">  <span class="keyword">let</span> screenHeight = wx.getSystemInfoSync().screenHeight</span><br><span class="line">  <span class="keyword">let</span> bottom = wx.getSystemInfoSync().safeArea.bottom</span><br><span class="line">  <span class="keyword">return</span> screenHeight !== bottom</span><br><span class="line">&#125;</span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <p>解决了如何判断设备是iPhoneX的问题，就可以写代码了。</p>
            <figure class="highlight html">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="tag">&lt;<span class="name">view</span> <span class="attr">class</span>=<span class="string">&quot;bottom-button &#123;&#123;isIpX ? &#x27;view-IPX&#x27; : &#x27;&#x27;&#125;&#125;&quot;</span>&gt;</span>底部按钮<span class="tag">&lt;/<span class="name">view</span>&gt;</span></span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <h2 id="方案二：使用微信官方API，getSystemInfo-中的safeArea对象进行适配（推荐）"><a href="#方案二：使用微信官方API，getSystemInfo-中的safeArea对象进行适配（推荐）" class="headerlink" title="方案二：使用微信官方API，getSystemInfo()中的safeArea对象进行适配（推荐）"></a>方案二：使用微信官方API，getSystemInfo()中的safeArea对象进行适配（推荐）</h2>
            <p><strong>使用wx. getSystemInfo()中的safeArea对象获取底部小黑条的高度</strong></p>
            <p>step 1：使用上面讲的方法先判断是否是需要适配的iPhone机型<br>step 2：如果是需要适配的机型，使用safeArea中的bottom，得到安全区域底部纵坐标，然后使用screenHeight减去bottom就能得到小黑条的高度。保存到localstorage里面，全局都可以使用。</p>
            <p><img src="" data-original="/images/FrontEnd/2530160-749b1110fedb55ef.webp" alt="image.png"></p>
            <h2 id="方案三：使用苹果官方推出适配方案css函数env-、constant-来适配-（推荐）"><a href="#方案三：使用苹果官方推出适配方案css函数env-、constant-来适配-（推荐）" class="headerlink" title="方案三：使用苹果官方推出适配方案css函数env()、constant()来适配 （推荐）"></a>方案三：使用苹果官方推出适配方案css函数env()、constant()来适配 （推荐）</h2>
            <p>苹果官方推荐使用<code>env()</code>，<code>constant()</code>来适配，建议使用该方案，不需要管数值具体是多少。这2个方法是什么呢？</p>
            <ul>
              <li>env()和constant()，是IOS11新增特性，Webkit的css函数，用于设定安全区域与边界的距离，有4个预定义变量： <ul>
                  <li>safe-area-inset-left：安全区域距离左边边界的距离</li>
                  <li>safe-area-inset-right：安全区域距离右边边界的距离</li>
                  <li>safe-area-inset-top：安全区域距离顶部边界的距离</li>
                  <li>safe-area-inset-bottom ：安全距离底部边界的距离</li>
                </ul>
              </li>
            </ul>
            <p>因为目标是需要对底部小黑条做适配，所以只需要关注<code>safe-area-inset-bottom</code>这个值。</p>
            <p>而env()和constant()函数有个必要的<strong>使用前提</strong>，当网页设置<code>viewport-fit=cover</code>的时候才生效，根据微信小程序的表现和我在实际真机测试时这两个函数生效，推测小程序里的<code>viewport-fit</code>默认是<code>cover</code>。</p>
            <p>有一点要注意，在IOS11.2系统以前，可以使用constant()函数，但是在IOS11.2系统以后，这个函数就被废弃了，被env()函数替代了。官方原话如下：</p>
            <blockquote>
              <p>The env() function shipped in iOS 11 with the name constant(). Beginning with Safari Technology Preview 41 and the iOS 11.2 beta, constant() has been removed and replaced with env(). You can use the CSS fallback mechanism to support both versions, if necessary, but should prefer env() going forward.</p>
            </blockquote>
            <p>所以我们在做屏幕适配时，需要这样写：</p>
            <figure class="highlight css">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br><span class="line">2</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="attribute">padding-bottom</span>: <span class="built_in">constant</span>(safe-area-inset-bottom); <span class="comment">/*兼容 IOS&lt;11.2*/</span></span><br><span class="line"><span class="attribute">padding-bottom</span>: <span class="built_in">env</span>(safe-area-inset-bottom); <span class="comment">/*兼容 IOS&gt;11.2*/</span></span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <p><strong>注意：</strong>env()和constant()需要同时存在，而且顺序不能换。</p>
            <h1 id="3-在H5上适配安全区域"><a href="#3-在H5上适配安全区域" class="headerlink" title="3. 在H5上适配安全区域"></a>3. 在H5上适配安全区域</h1>
            <p>在H5上适配安全区域就方便多了，采用viewport+env+constant方案。</p>
            <p>viewport-fit 默认有3个值：</p>
            <ul>
              <li>contain：可视窗口完全包含网页内容（左图）</li>
              <li>cover：网页内容完全覆盖可视窗口（右图）</li>
              <li>auto：默认值，此值不影响初始布局视图端口，并且整个web页面都是可查看的。</li>
            </ul>
            <p>contain和cover具体区别如下图：</p>
            <p><img src="" data-original="/images/FrontEnd/2530160-3554ca94b5fa64d4.webp" alt="viewport属性.png"></p>
            <p><strong>而我们需要将viewport设置为cover，env和constant才能生效。设置代码如下：</strong></p>
            <figure class="highlight xml">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width,initial-scale=1.0,viewport-fit=cover&quot;</span>&gt;</span></span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <p>同时设置env和constant代码，同样env()和constant()需要同时存在，而且顺序不能换。</p>
            <figure class="highlight css">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="comment">/* 可以通过增加padding-bottom来适配 */</span></span><br><span class="line"><span class="attribute">padding-bottom</span>: <span class="built_in">constant</span>(safe-area-inset-bottom); <span class="comment">/*兼容 IOS&lt;11.2*/</span></span><br><span class="line"><span class="attribute">padding-bottom</span>: <span class="built_in">env</span>(safe-area-inset-bottom); <span class="comment">/*兼容 IOS&gt;11.2*/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 可以通过margin-bottom来适配 */</span></span><br><span class="line"><span class="attribute">margin-bottom</span>: <span class="built_in">constant</span>(safe-area-inset-bottom);</span><br><span class="line"><span class="attribute">margin-bottom</span>: <span class="built_in">env</span>(safe-area-inset-bottom);</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 或者改变高度*/</span></span><br><span class="line"><span class="attribute">height</span>: <span class="built_in">calc</span>(<span class="number">55px</span> +  <span class="built_in">constant</span>(safe-area-inset-bottom));</span><br><span class="line"><span class="attribute">height</span>: <span class="built_in">calc</span>(<span class="number">55px</span> +  <span class="built_in">env</span>(safe-area-inset-bottom));</span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <p>也可以在底部添加一个空白的div颜色块来做适配。</p>
            <p><strong>还有一种是使用 @supports 隔离兼容样式</strong></p>
            <p>可以使用 @supports 来隔离兼容样式，当浏览器支持<code>bottom: constant(safe-area-inset-bottom)</code>或者<code>bottom: env(safe-area-inset-bottom)</code>的时候，<code>bottom-button</code>类就会新增<code>margin-bottom</code>的样式</p>
            <figure class="highlight css">
              <table>
                <tr>
                  <td class="gutter">
                    <pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre>
                  </td>
                  <td class="code">
                    <pre><span class="line"><span class="keyword">@supports</span> (<span class="attribute">bottom</span>: constant(safe-area-inset-bottom)) <span class="keyword">or</span> (<span class="attribute">bottom</span>: env(safe-area-inset-bottom)) &#123; </span><br><span class="line">    <span class="selector-class">.bottom-button</span> &#123;</span><br><span class="line">        <span class="attribute">margin-bottom</span>: <span class="built_in">constant</span>(safe-area-inset-bottom);</span><br><span class="line">        <span class="attribute">margin-bottom</span>: <span class="built_in">env</span>(safe-area-inset-bottom);  </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre>
                  </td>
                </tr>
              </table>
            </figure>

            <p>以上就是我对iPhoneX安全区域(Safe Area)底部小黑条在微信小程序和H5适配的总结。</p>
            <p>如果对你有帮助的话，点赞、评论、赞赏都是对我的鼓励，也是支持我写下去的动力，谢谢！</p>
            <p>参考文章：</p>
            <ul>
              <li><a target="_blank" rel="noopener" href="https://links.jianshu.com/go?to=https://aotu.io/notes/2017/11/27/iphonex/">网页适配 iPhoneX，就是这么简单</a></li>
              <li><a target="_blank" rel="noopener" href="https://links.jianshu.com/go?to=https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/adaptivity-and-layout/">苹果官方开发者文档关于屏幕适配的说明</a></li>
              <li><a target="_blank" rel="noopener" href="https://links.jianshu.com/go?to=https://blog.csdn.net/qq_35844177/article/details/88238145">微信小程序吸底区域适配iPhone X</a></li>
              <li><a target="_blank" rel="noopener" href="https://links.jianshu.com/go?to=https://kangzubin.com/wxapp-iphonex/">微信小程序适配 iPhone X 总结</a></li>
            </ul>
            <h1 id="注意"><a href="#注意" class="headerlink" title="注意"></a>注意</h1>
            <p>当给<code>html</code> <code>body</code> 设置高度<code>100%</code>的时候会自动增加安全区域，所以非必要的时候不要用这个用法，想尽办法用其他方法替换</p>
            <h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1>
            <blockquote>
              <p>本文原创发布于微信公众号「程序员张晴天」，欢迎关注第一时间获取最新分享，一起进步。</p>
            </blockquote>
            <p><a target="_blank" rel="noopener" href="https://www.jianshu.com/p/4e410eddff66">https://www.jianshu.com/p/4e410eddff66</a></p>

          </div>





          <footer class="post-footer">
            <div class="post-tags">
              <a href="/tags/iPhone%E5%AE%89%E5%85%A8%E5%8C%BA%E5%9F%9F/" rel="tag"># iPhone安全区域</a>
              <a href="/tags/Safe-Area/" rel="tag"># Safe Area</a>
              <a href="/tags/%E9%80%82%E9%85%8D/" rel="tag"># 适配</a>
            </div>



            <div class="post-nav">
              <div class="post-nav-item">
                <a href="/blob/2020-09-03-monitor-the-loading-progress-of-css-background-image/" rel="prev" title="监听CSS背景图片加载进度">
                  <i class="fa fa-chevron-left"></i> 监听CSS背景图片加载进度
                </a>
              </div>
              <div class="post-nav-item">
                <a href="/blob/2020-09-09-rollup-uses-the-plug-in-rollup-plugin-babel-of-babel-7-version-to-report-errors/" rel="next" title="rollup 使用babel7版本的插件rollup-plugin-babel报错解决办法">
                  rollup 使用babel7版本的插件rollup-plugin-babel报错解决办法 <i class="fa fa-chevron-right"></i>
                </a>
              </div>
            </div>
          </footer>
        </article>
      </div>







      <script>
        window.addEventListener('tabs:register', () => {
          let {
            activeClass
          } = CONFIG.comments;
          if (CONFIG.comments.storage) {
            activeClass = localStorage.getItem('comments_active') || activeClass;
          }
          if (activeClass) {
            const activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
            if (activeTab) {
              activeTab.click();
            }
          }
        });
        if (CONFIG.comments.storage) {
          window.addEventListener('tabs:click', event => {
            if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
            const commentClass = event.target.classList[1];
            localStorage.setItem('comments_active', commentClass);
          });
        }
      </script>
    </div>
  </main>

  <footer class="footer">
    <div class="footer-inner">


      <div class="copyright">
        &copy;
        <span itemprop="copyrightYear">2021</span>
        <span class="with-love">
          <i class="fa fa-heart"></i>
        </span>
        <span class="author" itemprop="copyrightHolder">holidaypenguin</span>
      </div>
      <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.js.org/mist/" class="theme-link" rel="noopener" target="_blank">NexT.Mist</a> 强力驱动
      </div>

    </div>
  </footer>


  <script size="300" alpha="0.1" zIndex="-1" src="https://cdn.jsdelivr.net/npm/ribbon.js@1.0.2/dist/ribbon.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/animejs@3.2.1/lib/anime.min.js"></script>
  <script src="/js/love.js"></script>

  <script src="/js/development.js"></script>
  <script src="/js/utils.js"></script>
  <script src="/js/motion.js"></script>
  <script src="/js/schemes/muse.js"></script>
  <script src="/js/next-boot.js"></script>


  <script src="/js/local-search.js"></script>









  <script>
    (function() {
      function leancloudSelector(url) {
        url = encodeURI(url);
        return document.getElementById(url).querySelector('.leancloud-visitors-count');
      }

      function addCount(Counter) {
        const visitors = document.querySelector('.leancloud_visitors');
        const url = decodeURI(visitors.id);
        const title = visitors.dataset.flagTitle;

        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({
            url
          })))
          .then(response => response.json())
          .then(({
            results
          }) => {
            if (results.length > 0) {
              const counter = results[0];
              leancloudSelector(url).innerText = counter.time + 1;
              Counter('put', '/classes/Counter/' + counter.objectId, {
                  time: {
                    '__op': 'Increment',
                    'amount': 1
                  }
                })
                .catch(error => {
                  console.error('Failed to save visitor count', error);
                });
            } else {
              Counter('post', '/classes/Counter', {
                  title,
                  url,
                  time: 1
                })
                .then(response => response.json())
                .then(() => {
                  leancloudSelector(url).innerText = 1;
                })
                .catch(error => {
                  console.error('Failed to create', error);
                });
            }
          })
          .catch(error => {
            console.error('LeanCloud Counter Error', error);
          });
      }

      function showTime(Counter) {
        const visitors = document.querySelectorAll('.leancloud_visitors');
        const entries = [...visitors].map(element => {
          return decodeURI(element.id);
        });

        Counter('get', '/classes/Counter?where=' + encodeURIComponent(JSON.stringify({
            url: {
              '$in': entries
            }
          })))
          .then(response => response.json())
          .then(({
            results
          }) => {
            for (let url of entries) {
              const target = results.find(item => item.url === url);
              leancloudSelector(url).innerText = target ? target.time : 0;
            }
          })
          .catch(error => {
            console.error('LeanCloud Counter Error', error);
          });
      }

      const {
        app_id,
        app_key,
        server_url
      } = {
        "enable": true,
        "app_id": "povuqNsSqFodlakVIwtEX5kb-gzGzoHsz",
        "app_key": "zXD40RDtDB3DMtpC89k0AK7g",
        "server_url": null,
        "security": false
      };

      function fetchData(api_server) {
        const Counter = (method, url, data) => {
          return fetch(`${api_server}/1.1${url}`, {
            method,
            headers: {
              'X-LC-Id': app_id,
              'X-LC-Key': app_key,
              'Content-Type': 'application/json',
            },
            body: JSON.stringify(data)
          });
        };
        if (CONFIG.page.isPost) {
          if (CONFIG.hostname !== location.hostname) return;
          addCount(Counter);
        } else if (document.querySelectorAll('.post-title-link').length >= 1) {
          showTime(Counter);
        }
      }

      const api_server = app_id.slice(-9) === '-MdYXbMMI' ? `https://${app_id.slice(0, 8).toLowerCase()}.api.lncldglobal.com` : server_url;

      if (api_server) {
        fetchData(api_server);
      } else {
        fetch('https://app-router.leancloud.cn/2/route?appId=' + app_id)
          .then(response => response.json())
          .then(({
            api_server
          }) => {
            fetchData('https://' + api_server);
          });
      }
    })();
  </script>



<script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(n){n.imageLazyLoadSetting.processImages=o;var e=n.imageLazyLoadSetting.isSPA,i=n.imageLazyLoadSetting.preloadRatio||1,r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]"));function o(){e&&(r=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")));for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(n.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];t=o,e=function(){r=r.filter(function(t){return o!==t})},n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,e&&e()},t.src!==i&&(n.src=i)}()}o(),n.addEventListener("scroll",function(){var t,e;t=o,e=n,clearTimeout(t.tId),t.tId=setTimeout(function(){t.call(e)},500)})}(this);</script></body>

</html>